package com.mybatis.boost.extend.mapper;

import lombok.Setter;
import org.mybatis.spring.mapper.ClassPathMapperScanner;
import org.mybatis.spring.mapper.MapperFactoryBean;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.boot.autoconfigure.AutoConfigurationPackages;
import org.springframework.context.EnvironmentAware;
import org.springframework.context.ResourceLoaderAware;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.env.Environment;
import org.springframework.core.io.ResourceLoader;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.util.ClassUtils;
import org.springframework.util.StringUtils;

import java.lang.annotation.Annotation;
import java.util.ArrayList;
import java.util.List;

/**
 * If you want more power, you can explicitly use MapperScan
 *
 * @author jearton
 * @see org.mybatis.spring.annotation.MapperScan
 * @since 2017/2/6
 */
public class AutoConfiguredMapperScannerRegistrar implements ImportBeanDefinitionRegistrar, EnvironmentAware,
        ResourceLoaderAware, BeanFactoryAware {

    @Setter
    private ResourceLoader resourceLoader;

    @Setter
    private BeanFactory beanFactory;

    private MapperScanProperties mapperScanProperties;

    @Override
    public void setEnvironment(Environment environment) {
        mapperScanProperties = new MapperScanProperties(environment);
    }

    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
        ClassPathMapperScanner scanner = new ClassPathMapperScanner(registry);

        if (resourceLoader != null) {
            scanner.setResourceLoader(resourceLoader);
        }

        Class<? extends Annotation> annotationClass = mapperScanProperties.getAnnotationClass();
        if (!Annotation.class.equals(annotationClass)) {
            scanner.setAnnotationClass(annotationClass);
        }

        Class<?> markerInterface = mapperScanProperties.getMarkerInterface();
        if (!Class.class.equals(markerInterface)) {
            scanner.setMarkerInterface(markerInterface);
        }

        Class<? extends MapperFactoryBean> mapperFactoryBeanClass = mapperScanProperties.getFactoryBean();
        if (!MapperFactoryBean.class.equals(mapperFactoryBeanClass)) {
            scanner.setMapperFactoryBean(BeanUtils.instantiateClass(mapperFactoryBeanClass));
        }

        scanner.registerFilters();

        List<String> basePackages = new ArrayList<>();
        for (String pkg : mapperScanProperties.getBasePackages()) {
            if (StringUtils.hasText(pkg)) {
                basePackages.add(pkg);
            }
        }
        for (Class<?> clazz : mapperScanProperties.getBasePackageClasses()) {
            basePackages.add(ClassUtils.getPackageName(clazz));
        }
        if (basePackages.size() == 0) {
            basePackages.addAll(AutoConfigurationPackages.get(this.beanFactory));
        }
        scanner.doScan(StringUtils.toStringArray(basePackages));
    }
}
